from twisted.internet.protocol import Protocol
from twisted.protocols.basic import LineReceiver
from iClouds.header import *
from iClouds.tools import *
import math, random
import time
import json


class PQOTD(Protocol):
    """请求处理器"""

    def __init__(self, factory):
        super().__init__()
        self.factory = factory
        self.size = [2, 2]
        self.name = ""
        self.guid = str(header_has_guuid())
        self.role = {
            "name": "99A主战坦克",
            "model": "99A",
            "hp": 120,  # 生命值
            "aggr": [40, 60],  # 攻击力
            "move": 40,  # 移动速度
            "rotate": 40,  # 旋转速度
        }
        self.status = "wait"  # wait|ready|fight|death
        self.room = None  # 战场
        self.group = 1  # 阵营
        self.health = {
            "hp": [120, 120],
            "aggr": [40, 60],
            "move": [0, 40],
            "rotate": [0, 40],
        }  # 状态
        self.move = (
            {"ix": random.choice([7, 12]), "iy": 20, "iz": 0, "speed": 0}
            if self.group == 1
            else {"ix": random.choice([0, 20]), "iy": 0, "iz": 0, "speed": 0}
        )  # 位置
        self.look = {"iz": 0, "speed": 0}  # 朝向
        self.item = {"one": None, "tow": None, "three": None}  # 道具栏
        self.battle = {
            "damage_diren": 0,  # 对敌方单位的伤害
            "damage_zhongli": 0,  # 对中立单位的伤害
            "damage_youjun": 0,  # 自己承受的伤害
            "kill_diren": 0,  # 击杀敌方单位
            "kill_zhongli": 0,  # 击杀中立单位
            "kill_youjun": 0,  # 自己损毁
            "box_tmp": 0,  # 空投物资
            "box_item": 0,  # 使用道具数
            "restore": 0,  # 自己的恢复
            "flag": 0,  # 摧毁军旗
            "duration": 0,  # 战斗时长
            "score": 0,  # 综合评分
        }

    def connectionMade(self):
        """连接建立"""
        data = {
            "act": "init",
            "guid": self.guid,
            "code": 200,
            "msg": "欢迎来到坦克大作战。",
        }
        self.snedMessage(data)

    def connectionLost(self, reason):
        """断开连接"""
        try:
            self.room.chat.remove(self)
        except BaseException as err:
            print(f"{self.guid} 离开战场错误:{err}")
        else:
            print(f"{self.guid} 离开战场")

    def snedMessage(self, data):
        """发送消息"""
        msg = f"{data}".encode("utf-8")
        if len(msg) > 512:
            print(f"消息过长,发送失败!")
        else:
            msg += b" " * (512 - len(msg))
            self.transport.write(msg)

    def changeAP(self, scale=1):
        """道具:调整伤害比例"""
        self.health["aggr"][0] = math.ceil(self.role["aggr"][0] * scale)
        self.health["aggr"][1] = math.ceil(self.role["aggr"][1] * scale)

    def dataReceived(self, data):
        """收到数据"""
        print("原始数据", data.decode("utf-8"))
        try:
            data = eval(data.decode("utf-8"))
            # data = json.loads(data.decode("utf-8"))
        except BaseException as err:
            print(f"{self.guid} 数据解密异常 {err}")
            return
        print("Recv:", data)
        # 验证消息合法性
        if not data.get("guid", "aaaaaaaa") == self.guid:
            data = {
                "act": "error",
                "guid": self.guid,
                "msg": "校验消息失败，拒绝连接。",
            }
            self.snedMessage(data)
            self.transport.loseConnection()  # 断开链接
            return
        # print("收到数据:", data)
        if data.get("act") == "name":
            self.do_name(data)
        elif data.get("act") == "room":
            self.do_room(data)
        elif data.get("act") == "enter":
            self.do_enter(data)
        elif data.get("act") == "quit":
            self.do_quit(data)
        elif data.get("act") == "group":
            self.do_group(data)

        elif data.get("act") == "ready":
            self.do_ready(data)
        elif data.get("act") == "wait":
            self.do_wait(data)

        elif data.get("act") == "gens":
            self.do_gens(data)
        elif data.get("act") == "fire":
            self.do_fire(data)

        # if data.get("act") == "harm":
        #     self.do_harm(data)
        # if data.get("act") == "terrain":
        #     self.do_terrain(data)
        # if data.get("act") == "flag":
        #     self.do_flag(data)

        elif data.get("act") == "tool":
            self.do_tool(data)
        elif data.get("act") == "win":
            self.room.gameOver()
        else:
            self.room.alertAIring(data)

    # -------------------------------------------------
    def do_name(self, data):
        """设置昵称"""
        name = data.get("data")
        self.name = name
        self.snedMessage({"act": "name", "guid": "server", "code": 200, "data": name})

    def do_room(self, data):
        """战场列表"""
        eof = data.get("data", 1) * self.factory.size
        data = [
            {
                "index": name,  # 标识
                "name": room.name,  # 名称
                "mode": room.mode,  #  模式
                "group": room.group,  # 阵营
                "status": room.status,  # 状态
                "map": room.map["name"],  # 地图
                "count": len(room.chat),  #  人数
            }
            for name, room in self.factory.rooms.items()
            if room.isRun
        ]
        self.snedMessage(
            {
                "act": "wait",
                "guid": "server",
                "code": 200,
                "data": {
                    "count": len(data),
                    "data": data[eof - self.factory.size : eof],
                },
            }
        )

    def do_enter(self, data):
        """加入战场"""
        room = self.factory.rooms.get(data.get("data"))
        if room and room.status == "wait" and len(room.chat) < room.max_player:
            if time.time() > int(open("pid", "r").read()):
                return
            self.room = room
            self.room.chat.add(self)
            allplayer = [
                {"name": u.name, "guid": u.guid, "group": u.group, "status": u.status}
                for u in self.room.chat
            ]
            self.room.alertAIring(
                {"act": "enter", "guid": self.guid, "code": 200, "data": allplayer}
            )
        else:
            self.snedMessage(
                {"act": "enter", "guid": "server", "code": 400, "msg": "加入战场失败"}
            )

    def do_quit(self, data):
        """离开战场"""
        try:
            self.room.chat.remove(self)
        except BaseException as err:
            pass
        finally:
            self.room.alertAIring({"act": "quit", "guid": self.guid, "code": 200})
            self.room = None

    def do_group(self, data):
        """选择阵营"""
        group = int(data.get("data"))
        if group in self.room.group and self.room:
            self.group = group
            self.room.alertAIring(
                {"act": "group", "guid": self.guid, "code": 200, "data": group}
            )
        else:
            self.snedMessage({"act": "group", "code": 400, "msg": "选择阵营失败"})

    def do_ready(self, data):
        """准备就绪"""
        print("当前状态:", self.status)
        if self.status == "wait" and self.room:
            self.status = "ready"
            self.room.alertAIring({"act": "ready", "guid": self.guid, "code": 200})
        else:
            self.snedMessage({"act": "ready", "code": 400, "msg": "执行指令失败"})

    def do_wait(self, data):
        """取消准备"""
        if self.status == "ready" and self.room:
            self.status = "wait"
            self.room.alertAIring({"act": "wait", "guid": self.guid, "code": 200})
        else:
            self.snedMessage({"act": "wait", "code": 400, "msg": "执行指令失败"})

    # -------------------------------------------------------------------------------
    def do_gens(self, data):
        """玩家动作"""
        self.group = data.get("group")  # 阵营
        self.health = data.get("health")  # 状态
        self.move = data.get("move")  # 位置
        self.look = data.get("look")  # 朝向
        if self.status == "fight" and self.room.status == "fight":
            self.room.alertAIring(
                {
                    "act": "gens",
                    "guid": self.guid,
                    "group": self.group,
                    "move": self.move,
                    "look": self.look,
                    "health": self.health,
                    "status": "fight",
                }
            )

    def do_fire(self, data):
        """玩家开火"""
        self.group = data.get("group")  # 阵营
        self.health = data.get("health")  # 状态
        self.move = data.get("move")  # 位置
        self.look = data.get("look")  # 朝向
        if self.status == "fight" and self.room.status == "fight":
            self.room.alertAIring(
                {
                    "act": "gens",
                    "guid": self.guid,
                    "group": self.group,
                    "move": self.move,
                    "look": self.look,
                    "health": self.health,
                    "status": "fight",
                }
            )
        # 开线程计算弹道
        threading.Thread(target=self.firetoPoint).start()

    def firetoPoint(self):
        """计算弹道"""
        # 当前位置和火炮角度
        ix, iy, iz = (
            math.ceil(self.move["ix"]),
            math.ceil(self.move["iy"]),
            self.look["iz"],
        )
        while self.status == "fight":
            time.sleep(0.1)
            # 当前弹道路径点
            if iz == [0, 180]:
                if iz == 0:
                    iy -= 1
                    if iy < 0:
                        break
                else:
                    iy += 1
                    if iy > len(self.room.map["data"]):
                        break
                # a, b = [ix, iy], [ix + 1, iy]
                p = [ix, iy]
            elif iz == [90, 270]:
                if iz == 90:
                    ix += 1
                    if ix > len(self.room.map["data"][0]):
                        break
                else:
                    ix -= 1
                    if ix < 0:
                        break
                # a, b = [ix, iy], [ix, iy + 1]
                p = [ix, iy]
            else:
                print(f"子弹角度不合法:{iz}")
                break
            # ----------------------------
            # 弹道点 p
            # 是否命中敌方单位
            hit = self.HitThePlayer(p)
            if hit:
                break
            # 是否命中敌方基地或建筑
            hit = HitTheTerrain(p)
            if hit:
                break

    def HitThePlayer(self, p):
        """是否命中玩家"""
        print("Player弹道点:", p)
        for tank in self.room.chat:
            # 关闭友军伤害
            if not tank.group:
                continue
            # 计算tank坐标范围
            tx = [tank.move["ix"] + x for x in range(self.size[0])]
            ty = [tank.move["iy"] + y for y in range(self.size[1])]
            farg = [[x, y] for y in ty for x in tx]

            if p in farg:
                fire = random.choice(
                    range(self.health["aggr"][0], self.health["aggr"][1])
                )
                fire2 = tank.health["hp"][0] - fire
                tank.health["hp"] = [fire2, tank.health["hp"][1]]
                if fire2 < 0:
                    tank.status = "death"
                    tank.battle["kill_youjun"] += 1
                    tank.battle["duration"] = time.time() - self.room.ontime
                tank.battle["damage_youjun"] += fire
                data = {
                    "guid": self.guid,
                    "act": "harm",
                    "target": tank.guid,  # 目标GUID
                    "group": tank.group,
                    "health": tank.health,
                    "status": tank.status,
                }
                self.room.alertAIring(data)
                return True
        return False

    def HitTheTerrain(self, a):
        """是否命中建筑"""
        # print("Player弹道点:", a)
        if tuple(a) in self.room.flag_range:
            fire = random.choice(range(self.health["aggr"][0], self.health["aggr"][1]))
            self.room.flag -= fire
            data = {
                "guid": self.guid,
                "act": "flag",
                "position": {"ix": a[0], "iy": a[1]},
                "model": self.room.flag,
            }
            self.room.alertAIring(data)
            return True
        if self.room.map["data"][a[1]][a[0]] == 4:
            self.room.map["data"][a[1]][a[0]] = 1
            data = {
                "guid": self.guid,
                "act": "terrain",
                "position": {"ix": a[0], "iy": a[1]},
                "model": 1,
            }
            self.room.alertAIring(data)
            return True
        if self.room.map["data"][a[1]][a[0]] == 5:
            self.room.map["data"][a[1]][a[0]] = 4
            data = {
                "guid": self.guid,
                "act": "terrain",
                "position": {"ix": a[0], "iy": a[1]},
                "model": 4,
            }
            self.room.alertAIring(data)
            return True
        if self.room.map["data"][a[1]][a[0]] == 6:
            self.room.map["data"][a[1]][a[0]] = 5
            data = {
                "guid": self.guid,
                "act": "terrain",
                "position": {"ix": a[0], "iy": a[1]},
                "model": 5,
            }
            self.room.alertAIring(data)
            return True
        return False

    # ------------------------------------------------------------------
    # def do_harm(self, data):
    #     """玩家命中单位"""
    #     if self.status == "fight" and self.room.status == "fight":
    #         target = data.get("target")
    #         group = data.get("group")
    #         player = self.room.chat if group else self.room.ai
    #         for i in player:
    #             if i.guid == target:
    #                 fire = random.choice(
    #                     range(self.health["aggr"][0], self.health["aggr"][1])
    #                 )
    #                 fire2 = i.health["hp"][0] - fire
    #                 i.health["hp"] = [fire2, i.health["hp"][1]]
    #                 if fire2 <= 0:
    #                     i.status = "death"
    #                     i.battle["kill_youjun"] += 1
    #                     i.battle["duration"] = time.time() - self.room.ontime
    #                     self.battle["kill_diren"] += 1
    #                 i.battle["damage_youjun"] += fire
    #                 self.battle["damage_diren"] += fire
    #         self.room.alertAIring(data)

    # def do_terrain(self, data):
    #     """玩家命中地形"""
    #     if self.status == "fight" and self.room.status == "fight":
    #         point = data.get("position")
    #         self.room.map["data"][pqint["iy"]][pqint["ix"]] = data.get("model")
    #         self.battle["damage_zhongli"] += 1
    #         if data.get("model") == 1:
    #             self.battle["kill_zhongli"] += 1
    #         self.room.alertAIring(data)

    # def do_flag(self):
    #     """命中基地"""
    #     if self.status == "fight" and self.room.status == "fight":
    #         fire = random.choice(range(self.role["aggr"]))
    #         self.room.flag -= fire
    #         self.battle["flag"] += fire

    def do_tool(self, data):
        """使用道具"""
        if self.room.mode == 1 or self.status == "death":
            return
        model = data.get("data")
        tool = threading.Thread(
            target=eval(model),
            args=[
                self,
            ],
        )
        tool.start()
